using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using System;

namespace IQIGame.Onigao.Logic
{
    public class LgEntityLinearMove : LogicBaseEntityComponent
    {
        public override uint MaxStore => 50;
        private LevelEntity _entity;
        private float _initSpeedPFrame;
        private Vector3Logic _stopPoint;
        private EntityMoveDirType _dirType;
        private Vector3Logic _startPoint;
        private Vector3Logic _moveDir;
        private float _accelerationPFrame;
        private int _startFrame = -1;
        private int _stopFrame = -1;

        public Vector3Logic stopPoint => _stopPoint;

        public override void Awake(BaseEntity entity)
        {
            _entity = entity as LevelEntity;
        }

        /// <summary>
        /// 移动到指定点
        /// </summary>
        /// <param name="stopPoint"></param>
        /// <param name="initSpeed">初速度，每秒移动的厘米数</param>
        /// <param name="keepDir">是否保持朝向不变</param>
        public void MoveTo(Vector3Logic stopPoint, int initSpeed, EntityMoveDirType dirType)
        {
            //修正y值
            if (_entity.region.terrain.FindNearestPoint(stopPoint, out var realStopPoint))
            {
                _stopPoint = realStopPoint;
            }
            else
            {
                LogicLog.LogError($"目标位置{_stopPoint}非法。");
                _entity.RemoveComponent<LgEntityLinearMove>();
                return;
            }
            _dirType = dirType;
            _initSpeedPFrame = (float)initSpeed / LgLevelConst.FrameRate;
            _startPoint = _entity.position;
            Vector3Logic startToEnd = _stopPoint - _startPoint;
            _moveDir = startToEnd.normalized;
            float distance = startToEnd.magnitude;
            _accelerationPFrame = -_initSpeedPFrame * _initSpeedPFrame / (distance * 2);
            int totalFrame = (int)Math.Ceiling(_initSpeedPFrame / -_accelerationPFrame);
            _startFrame = _entity.region.level.levelFrame;
            _stopFrame = _entity.region.level.levelFrame + totalFrame;
            _entity.OccupiedBy(EntityOccupationStatus.BeingPush, 1);
        }

        public override void LogicOnUpdate()
        {
            int levelFrame = _entity.region.level.levelFrame;
            bool reachStopPoint = false;
            if (levelFrame < _stopFrame)
            {
                int elapsedFrame = levelFrame - _startFrame;
                //匀减速运动距离计算
                float moveDis = _initSpeedPFrame * elapsedFrame + 0.5f * _accelerationPFrame * elapsedFrame * elapsedFrame;
                if (moveDis >= 0)
                {
                    Vector3Logic nextPos = _startPoint + _moveDir * moveDis;
                    Vector3Logic curToStop = _stopPoint - nextPos;
                    reachStopPoint = curToStop == Vector3Logic.zero;
                    if (!reachStopPoint)
                    {
                        Vector3Logic curToStopDir = curToStop.normalized;
                        //获取【当前目标->终点】和【初始->终点】的夹角，如果大于0表示夹角是锐角，前进方向基本没变
                        float dot = Vector3Logic.Dot(curToStopDir, _moveDir);
                        if (dot >= 0.99939f) //方向基本没改
                        {
                            float curSpeedPFrame = _initSpeedPFrame + _accelerationPFrame * elapsedFrame;
                            MoveTo(nextPos, curSpeedPFrame * LgLevelConst.FrameRate);
                            //如果要实现碰到阻挡自动停下来，这里在移动后需要判断一次落点，如果上一个路径点到落点的矢量
                            //和上一个路径点到终点的矢量夹角过大，则说明碰到了障碍物，需要停下来
                        }
                        else //方向改了说明越过了终点。
                        {
                            reachStopPoint = true;
                        }
                    }
                }
            }
            else if (_stopFrame != -1)
            {
                reachStopPoint = true;
            }
            if (reachStopPoint)
            {
                StopMoveAt(_stopPoint);
            }
        }

        private void MoveTo(Vector3Logic targetPoint, float curSpeed)
        {
            if (!_entity.MoveInNavMesh(targetPoint, curSpeed / _entity.defaultMoveSpeed, true, _dirType))
            {
                LogicLog.LogError($"实体移动到{targetPoint}失败。");
                StopMoveAt(_stopPoint);
            }
        }

        private void StopMoveAt(Vector3Logic stopPoint)
        {
            MoveTo(stopPoint, _entity.moveSpeed);
            _entity.RemoveComponent<LgEntityLinearMove>();
        }

        public override void OnRelease()
        {
            _entity.ReleaseOccupation(EntityOccupationStatus.BeingPush);
            _entity = null;
            _startPoint = default;
            _stopPoint = default;
            _moveDir = default;
            _initSpeedPFrame = 0;
            _accelerationPFrame = 0;
            _startFrame = -1;
            _stopFrame = -1;
            _dirType = EntityMoveDirType.None;
        }
    }
}
